package cast

import (
	"fmt"
	"sort"
	"strings"

	"gitee.com/u-language/u-language/ucom/ast"
	"gitee.com/u-language/u-language/ucom/data"
	"gitee.com/u-language/u-language/ucom/internal/errutil"
	"gitee.com/u-language/u-language/ucom/internal/utils"
)

// generateCNodeStr 将C代码节点转换为字符串写入buf
func generateCNodeStr(n []ast.Node, buf *strings.Builder) {
	for _, v := range n {
		if v == nil {
			buf.WriteString("<nil>")
			continue
		}
		buf.WriteString(v.String())
	}
}

// generateInit 生成隐式调用init函数 返回init函数定义
//   - PackageName 是包名
//   - isInitFunc是否有自定义init函数
//   - node 是变量初始化节点
//   - fbuf 写入声明
//   - importLocal 是自己导入的包
//   - isImported 是否被导入
func generateInit(PackageName string, isInitFunc bool, node []ast.ASSIGNInfo, fbuf *strings.Builder, importLocal []*Package, isImported bool) string {
	var buf strings.Builder
	vil := len(node)
	var decl string = utils.GeneratePackageSymbol(PackageName, "init")
	//生成隐式init函数声明
	fbuf.WriteString("// --- 隐式init函数声明 ---\n")
	fbuf.WriteString("void ")
	fbuf.WriteString(decl)
	fbuf.WriteString("();\n")
	//生成隐式init函数定义
	f := ast.FuncNode{}
	f.FuncInfo = &ast.FuncInfo{}
	f.Name = decl
	f.C(&buf)
	fbuf.WriteString("\n")
	if !isImported { //如果不是被导入的包
		generateImportInitCallAll(importLocal, &buf)
	}
	buf.WriteString("\n")
	for i := 0; i < vil; i++ {
		node[i].Ptr.C(&buf)
	}
	if isInitFunc { //如果有自定义的init函数
		buf.WriteString("// --- 调用自定义init函数 ---\n")
		//调用自定义init函数
		buf.WriteString(utils.GeneratePackageSymbol(PackageName, "init__user"))
		buf.WriteString("();\n")
	}
	buf.WriteString("\n}\n")
	return buf.String()
}

// generateImportInitCallAll生成被导入包的init调用
//   - importLocal 是自己导入的包
//   - buf 是写入缓冲区
//
// 因为被依赖的先入栈，从栈顶开始遍历，所以保证如果包p导入包q，q的init执行结束在p的init执行开始之前
func generateImportInitCallAll(importLocal []*Package, buf *strings.Builder) {
	var stack = data.NewRemoveDupStrck[string](false)
	for _, v := range importLocal {
		generateImportInitCall(&stack, v.importLocal)
		stack.Push(v.packageName)
	}
	stack.Range(func(v string) {
		buf.WriteString(utils.GeneratePackageSymbol(v, "init"))
		buf.WriteString("();\n")
	})
}

// generateImportInitCall记录被导入包
//   - stack 是记录栈
//   - importLocal 是自己导入的包
func generateImportInitCall(stack *data.RemoveDupStrck[string], importLocal []*Package) {
	if len(importLocal) == 0 {
		return
	}
	for _, v := range importLocal {
		generateImportInitCall(stack, v.importLocal)
		stack.Push(v.packageName)
	}
}

// generateHeaderFile 生成头文件的内容
// 假设inAutoFreeFuncInfo已经排序了
func generateHeaderFile(slice []ast.CHeaderFile, inAutoFreeFuncInfo []ast.SymbolInfo, buf *strings.Builder) {
	sort.Slice(slice, func(i int, j int) bool { //排序是为了保证可复现的构建，和类型声明在最前面
		return nodeCmp(i, j, slice)
	})
	for _, v := range slice {
		v.N.CDecl(buf)
		buf.WriteString("\n")
	}
	for _, v := range inAutoFreeFuncInfo {
		generateInAutoFreeFuncDecl(v, buf)
	}
}

// nodeCmp i小于j返回true
//
// 比较规则
//   - 枚举最小
//   - 结构体第二小
//   - 其他依据行号大小，行号小的更小，如果行号相同，比较名称
func nodeCmp(i, j int, slice []ast.CHeaderFile) bool {
	switch in := slice[i].N.(type) {
	case *ast.EnumDecl:
		switch jn := slice[j].N.(type) {
		case *ast.EnumDecl:
			return in.Name < jn.Name
		default:
			return true
		}
	case *ast.StructDecl:
		switch jn := slice[j].N.(type) {
		case *ast.EnumDecl:
			return false
		case *ast.StructDecl:
			return in.Name < jn.Name
		default:
			return true
		}
	}
	switch slice[j].N.(type) {
	case *ast.EnumDecl:
		return false
	case *ast.StructDecl:
		return false
	}
	switch {
	case slice[i].Line < slice[j].Line:
		return true
	case slice[i].Line > slice[j].Line:
		return false
	}
	// 如果i和j的行数相等，则按节点名称进行比较
	return getName(slice[i].N) < getName(slice[j].N)
}

// getName函数用于获取节点的名称
func getName(n ast.Node) string {
	switch n := n.(type) {
	case *ast.VarNode:
		return n.Name
	case *ast.ConstNode:
		return n.Name
	case *ast.FuncNode:
		return n.Name
	case *ast.StructDecl:
		return n.Name
	case *ast.EnumDecl:
		return n.Name
	case *ast.MethodNode:
		return n.Name
	default:
		panic(errutil.NewErr2(errutil.CompileErr, fmt.Sprintf("未知的节点：%+v", n)))
	}
}

// generateCFile 将C代码转换为字符串写入buf
func generateCFile(nodes []ast.Node, buf *strings.Builder) {
	for i := 0; i < len(nodes); i++ {
		if nodes[i] == nil {
			continue
		}
		nodes[i].C(buf)
		buf.WriteString("\n")
	}
}

// 生成导入的包
//   - importLocal 保存被导入的包
//   - AstImportPackage 是被导入包的U抽象语法树
//   - importPackage 是所有被导入的包
func generateImport(importLocal *[]*Package, AstImportPackage []data.IsItARecursiveType, importPackage map[string]*Package) {
	mlen := len(AstImportPackage)
	if importPackage == nil {
		importPackage = make(map[string]*Package, mlen)
	}
	*importLocal = make([]*Package, 0, mlen)
	for _, v := range AstImportPackage {
		k := v.(*ast.Package)
		_, ok := importPackage[k.My()]
		if ok {
			continue
		} else {
			tocp := NewPackage(k.Thread)
			tocp.AddUastSlice(k, importPackage)
			tocp.isImported = true
			importPackage[k.My()] = tocp
			*importLocal = append(*importLocal, tocp)
		}
	}
}

// generateCFile 将C代码转换为字符串写入buf,不写入换行
func generateCFileNoLF(nodes []ast.Node, buf *strings.Builder) {
	for i := 0; i < len(nodes); i++ {
		if nodes[i] == nil {
			continue
		}
		nodes[i].C(buf)
	}
}
